package cn.myword.wordTemple.util;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileReader;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.json.JSONUtil;
import cn.myword.wordTemple.entity.Table;
import cn.myword.wordTemple.tools.ParamGenerate;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import cn.myword.wordTemple.entity.ReciveData;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Pattern;


public class MyWordTemplateEngineUtil {
    private static final String TEMP_PATH = System.getProperty(
            "java.io.tmpdir") + "WordTemplateEngineUtil" + File.separator;
    private static final String TEMP_PATH_EXPORT = System.getProperty(
            "java.io.tmpdir") + "WordTemplateEngineUtilExport" + File.separator;
    private static final String TEMP_PATH_DOC = TEMP_PATH + "word" + File.separator;
    private static int rId = 1000;

    /**
     * 根据模板生成
     * 多表格的情况下，list数据需编号 :list0,list1,list2
     *
     * @param templatePath docx模板位置
     * @param ctx          map类型的数据格式，表格数据使用list
     * @return
     * @throws Exception
     * @since 思路是匹配到`list{xxx}`的时候才会去找list,listNum++
     */
    public static JSONObject generator(String templatePath, VelocityContext ctx) throws Exception {
        ZipUtil.unzip(templatePath, TEMP_PATH);
        Document document = new SAXReader().read(new File(TEMP_PATH_DOC + "document.xml"));
        changeCtx(ctx);

        System.out.println(JSONUtil.toJsonStr(ctx));
        Element root = document.getRootElement();
        Element body = root.element("body");
        List<Element> childNodes = body.elements("tbl");
        int listNum = 0;

        for (Element childNode : childNodes) {//处理所有tbl
            if (ctx.get("list" + listNum) == null) {
                System.out.println("list"+listNum+"为空，结束--------------------");
                break;
            }
            List<Map<String, Object>> list = (List<Map<String, Object>>) ctx.get("list" + listNum);//获取设置数据
            List<Element> trList = childNode.elements("tr");
            int trNum = 0;
            int i = 0;
            boolean hasLoopList = false;
            int loopNum=trList.size();
            boolean addNum=false;
            while (trNum < loopNum) {
                Element tr = trList.get(i);
                List<Element> tcList = tr.elements("tc");
                boolean hasLoop = false;
                Element copyElement = tr.createCopy();
                for (Element tc : tcList) {//一行走完
                    try {
                        Element contentElement = tc.element("p").element("r").element("t");
                        String content = contentElement.getText();

                        if (Pattern.matches(".*\\$\\{.*}", content)) {
                            Attribute name = contentElement.attribute("name");
                            String nameStr;
                            if (name == null) {//默认去就是null
                                nameStr = content.replaceAll("\\$\\{", "").replaceAll("}", "");//获取模板填写名
                                contentElement.setAttributeValue("name", nameStr);//设置节点名
                                name = contentElement.attribute("name");
                            }
                            nameStr = name.getText();
                            if ("img".equals(nameStr)) {
                                tc.element("p").element("r").remove(contentElement);
                                tc.element("p").remove(tc.element("p").element("bookmarkStart"));
                                tc.element("p").remove(tc.element("p").element("bookmarkEnd"));
                                Object img = list.get(trNum).get("img");
                                if(img!=null) {
                                    tc.element("p").element("r").add(
                                            createImgTemplate(String.valueOf(img)));
                                }

                            }
                            else {
                                String target=(String) ctx.get(nameStr);
                              /*  if(nameStr.contains("json")){//json表格串
                                    System.out.println("handle json!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
                                    if (target!=null) {
                                        for (String e : target.split("\n")) {
                                            if(!e.isEmpty()){
                                                Element tableCell = tc.addElement("w:tc");
                                                Element cellProperties = tableCell.addElement("w:tcPr");
                                                // 添加单元格内容
                                                Element cellText = tableCell.addElement("w:p").addElement("w:r").addElement("w:t");
                                                cellText.addText(e);
                                                System.out.println("add!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!   "+e);
                                            }
                                        }
                                    }
                                }else */
                                if (target!=null) {
                                    contentElement.setText(target);
                                }
                                //contentElement.setText("${list" + listNum + "_" + trNum + "_" + nameStr + "}");
                            }
                        }else if (Pattern.matches(".*list\\{.*}", content)) {
                            hasLoop = true;
                            hasLoopList=true;
                            loopNum=list.size();
                            if(!addNum){
                                trNum=0;
                                addNum=true;
                            }
                            Attribute name = contentElement.attribute("name");
                            String nameStr;
                            if (name == null) {//默认去就是null
                                nameStr = content.replaceAll("list\\{", "").replaceAll("}", "");//获取模板填写名
                                contentElement.setAttributeValue("name", nameStr);//设置节点名
                                name = contentElement.attribute("name");
                            }
                            nameStr = name.getText();
                            if ("img".equals(nameStr)) {
                                tc.element("p").element("r").remove(contentElement);
                                tc.element("p").remove(tc.element("p").element("bookmarkStart"));
                                tc.element("p").remove(tc.element("p").element("bookmarkEnd"));
                                Object img = list.get(trNum).get("img");
                                if(img!=null) {
                                    tc.element("p").element("r").add(
                                            createImgTemplate(String.valueOf(img)));
                                }

                            }
                            else {
                                String listData="list"+listNum+"_"+trNum+"_"+nameStr;
                                System.out.println(listData+"    ------------------------------");
                                List<HashMap<String,Object>> targetList=(List<HashMap<String,Object>>) ctx.get("list"+listNum);
                                HashMap<String,Object> hashMap=new HashMap<>();
                                hashMap=targetList.get(trNum);
                                String target=  hashMap.get(nameStr).toString();
                                System.out.println("target is  "+target);
                                if (target!=null)
                                    contentElement.setText(target);
                                //contentElement.setText("${list" + listNum + "_" + trNum + "_" + nameStr + "}");
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        System.out.println("-------------");
                    }
                }
              /*  if (trNum >= list.size() || (trNum + 1) > list.size()) {//表扫描结束
                    break;
                }
                else */
                if (hasLoop && copyElement != null) {
                    if(trNum+1 >= loopNum){
                        break;
                    }
                    childNode.add(copyElement);//加入表格
                    trList = childNode.elements("tr");//刷新获取
                }
                trNum++;
                i++;
            }
            if(hasLoopList) {
                listNum++;
            }
            System.out.println("node "+listNum+" run");
        }//所有table扫描完毕
        System.out.println("一共这么多"+childNodes.size()+"表，结束--------------------");
        FileOutputStream fileOutputStream = new FileOutputStream(TEMP_PATH_DOC + "document_format.xml");
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, StandardCharsets.UTF_8);
        XMLWriter writer = new XMLWriter(outputStreamWriter, OutputFormat.createPrettyPrint());
        writer.write(document);
        //fileOutputStream.close();
        writer.close();
        VelocityEngine ve = new VelocityEngine();
        ve.setProperty(VelocityEngine.FILE_RESOURCE_LOADER_PATH, TEMP_PATH_DOC);
        ve.init();
        Template t = ve.getTemplate("document_format.xml");
        FileWriter fileWriter = new FileWriter(TEMP_PATH_DOC + "document.xml",StandardCharsets.UTF_8);
        t.merge(ctx, fileWriter);
        fileWriter.flush();
        fileWriter.close();
        FileUtil.del(new File(TEMP_PATH_DOC + "document_format.xml"));
        String targetPath = TEMP_PATH_EXPORT + DateTime.now().toString("yyyyMMddHHmmSS") + ".docx";
        System.out.println("临时位置"+TEMP_PATH);
        File file=ZipUtil.zip(TEMP_PATH, targetPath);
        FileUtil.del(new File(TEMP_PATH));
        System.out.println("文件输出：" + targetPath);
        JSONObject jsonObject=new JSONObject();
        jsonObject.put("file",file);
        jsonObject.put("path",targetPath);
        return jsonObject;

    }

    private static void changeCtx(VelocityContext ctx) {
        for (int i = 0; i < 1000; i++) {
            Object o = ctx.get("list" + i);
            if (o != null) {
                List<Map<String, Object>> list = (List<Map<String, Object>>) o;
                for (int j = 0; j < list.size(); j++) {
                    Map<String, Object> map = list.get(j);
                    for (String s : map.keySet()) {
                        ctx.put("list" + i + "_" + j + "_" + s, map.get(s));
                        System.out.println("list" + i + "_" + j + "_" + s);
                    }
                }
            }
            else {
                break;
            }
        }

    }

    private static Element createImgTemplate(String path) throws IOException {
        String targetPath = TEMP_PATH + "word" + File.separator + "media" + File.separator + "image" + rId + path.substring(
                path.lastIndexOf("."));
        FileUtil.touch(targetPath);
        FileUtil.copy(path, targetPath, true);
        Element drawing = DocumentHelper.createElement("w:drawing");
        Element inline = DocumentHelper.createElement("wp:inline");
        inline.setAttributeValue("distT", "0");
        inline.setAttributeValue("distB", "0");
        inline.setAttributeValue("distL", "114300");
        inline.setAttributeValue("distR", "114300");
        drawing.add(inline);
        Element extent = DocumentHelper.createElement("wp:extent");
        extent.setAttributeValue("cx", "1609090");
        extent.setAttributeValue("cy", "1607185");
        inline.add(extent);
        Element effectExtent = DocumentHelper.createElement("wp:effectExtent");
        effectExtent.setAttributeValue("r", "10160");
        effectExtent.setAttributeValue("b", "12065");
        effectExtent.setAttributeValue("l", "0");
        effectExtent.setAttributeValue("t", "0");
        inline.add(effectExtent);
        Element docPr = DocumentHelper.createElement("wp:docPr");
        docPr.setAttributeValue("id", rId + "");
        docPr.setAttributeValue("name", "图片");
        docPr.setAttributeValue("descr", "图片");
        inline.add(docPr);

        Element cNvGraphicFramePr = DocumentHelper.createElement("wp:cNvGraphicFramePr");
        inline.add(cNvGraphicFramePr);
        Element graphicFrameLocks = DocumentHelper.createElement("a:graphicFrameLocks");
        graphicFrameLocks.setAttributeValue("xmlns:a", "http://schemas.openxmlformats.org/drawingml/2006/main");
        graphicFrameLocks.setAttributeValue("noChangeAspect", "1");
        cNvGraphicFramePr.add(graphicFrameLocks);
        Element graphic = DocumentHelper.createElement("a:graphic");
        graphic.setAttributeValue("xmlns:a", "http://schemas.openxmlformats.org/drawingml/2006/main");
        inline.add(graphic);

        Element graphicData = DocumentHelper.createElement("a:graphicData");
        graphicData.setAttributeValue("uri", "http://schemas.openxmlformats.org/drawingml/2006/picture");
        graphic.add(graphicData);
        Element pic = DocumentHelper.createElement("pic:pic");
        pic.setAttributeValue("xmlns:pic", "http://schemas.openxmlformats.org/drawingml/2006/picture");
        graphicData.add(pic);
        Element nvPicPr = DocumentHelper.createElement("pic:nvPicPr");
        pic.add(nvPicPr);
        Element cNvPr = DocumentHelper.createElement("pic:cNvPr");
        cNvPr.setAttributeValue("id", rId + "");
        cNvPr.setAttributeValue("name", "图片");
        cNvPr.setAttributeValue("descr", "图片");
        nvPicPr.add(cNvPr);
        Element cNvPicPr = DocumentHelper.createElement("pic:cNvPicPr");
        nvPicPr.add(cNvPicPr);
        Element picLocks = DocumentHelper.createElement("a:picLocks");
        picLocks.setAttributeValue("noChangeAspect", "1");
        cNvPicPr.add(picLocks);
        Element blipFill = DocumentHelper.createElement("pic:blipFill");
        pic.add(blipFill);
        Element blip = DocumentHelper.createElement("a:blip");
        // 图片位置
        blip.setAttributeValue("r:embed", "rId" + rId);
        blipFill.add(blip);

        Element stretch = DocumentHelper.createElement("a:stretch");
        blipFill.add(stretch);
        Element fillRect = DocumentHelper.createElement("a:fillRect");
        stretch.add(fillRect);
        Element spPr = DocumentHelper.createElement("pic:spPr");
        pic.add(spPr);
        Element xfrm = DocumentHelper.createElement("pic:xfrm");
        spPr.add(xfrm);
        Element off = DocumentHelper.createElement("a:off");
        off.setAttributeValue("x", "0");
        off.setAttributeValue("y", "0");
        xfrm.add(off);
        Element ext = DocumentHelper.createElement("a:ext");
        ext.setAttributeValue("cx", "1609090");
        ext.setAttributeValue("cy", "1607185");
        xfrm.add(ext);
        Element prstGeom = DocumentHelper.createElement("a:prstGeom");
        prstGeom.setAttributeValue("prst", "rect");
        spPr.add(prstGeom);

        Element avLst = DocumentHelper.createElement("a:avLst");
        prstGeom.add(avLst);

        String relFile = TEMP_PATH + "word" + File.separator + "_rels" + File.separator + "document.xml.rels";
        FileReader fileReader = new FileReader(relFile);
        String result = fileReader.readString().replaceAll("</Relationships>",
                "<Relationship Id=\"rId" + rId + "\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image\" " + "Target=\"media/image" + rId + (path.substring(
                        path.lastIndexOf("."))) + "\"/></Relationships>");

        FileWriter writer = new FileWriter(relFile + "temp");
        writer.write(result);
        writer.close();
        FileUtil.del(relFile);
        FileUtil.move(new File(relFile + "temp"), new File(relFile), true);
        FileUtil.del(relFile + "temp");
        rId++;
        return drawing;
    }

    public static void setParam(Map<String, Object> data, ReciveData reciveData){
        int n =0;//url参数替换
        for(String e:reciveData.getUrls()){
            data.put("url"+ (n+1),e);n++;
        }
        data.put("idsdes",reciveData.getIdsDes());
        List<Map<String, Object>> fullList = new ArrayList<>();
        List<HashMap<String,Object>> hashMapList=new ArrayList<>();
        HashMap<String,Object> hashMap=new HashMap<>();
        for (Table e:reciveData.getTables()) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("listparm1", e.get参数名());
            map.put("type1", e.get类型());
            map.put("des1", e.get描述());
            hashMap.put(e.get参数名(), ParamGenerate.generate(e.get类型()));
            fullList.add(map);
        }
        hashMapList.add(hashMap);
        List<Map<String, Object>> fullList_ll = new ArrayList<>();
        for (Table e:reciveData.getTables()) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("listparm1", e.get参数名());
            map.put("type1", e.get类型());
            map.put("des1", e.get描述());
            fullList_ll.add(map);
        }
        List<String> unitCode=new ArrayList<>();
        unitCode.add("createDate"); unitCode.add("modityDate"); unitCode.add("createUserId"); unitCode.add("modityUserId"); unitCode.add("deleteMark");
        List<Map<String, Object>> insertList = new ArrayList<>();
        for (Table e:reciveData.getTables()) {
            if(unitCode.contains(e.get参数名())){
                continue;
            }
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("listparm1", e.get参数名());
            map.put("type1", e.get类型());
            map.put("need1", e.get是否必须());
            map.put("des1", e.get描述());
            insertList.add(map);
        }
        List<Map<String, Object>> pageList = new ArrayList<>();
        for (Table e:reciveData.getPageTables()) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("listparm1", e.get参数名());
            map.put("type1", e.get类型());
            map.put("need1", "否");
            map.put("des1", e.get描述());
            pageList.add(map);
        }
        JSONObject jsonObject1=new JSONObject();
        jsonObject1.put("code",0);
        jsonObject1.put("msg","Sucess");
        jsonObject1.put("subCode",0);
        jsonObject1.put("subMsg",null);
        jsonObject1.put("data",hashMapList);
        JSONObject jsonObject2=new JSONObject();
        jsonObject2.put("code",0);
        jsonObject2.put("msg","Sucess");
        jsonObject2.put("subCode",0);
        jsonObject2.put("subMsg",null);
        JSONObject temp=new JSONObject();
        temp.put("page",1);
        temp.put("pages",1);
        temp.put("size",1);
        temp.put("total",1);
        temp.put("list",hashMapList);
        jsonObject2.put("data",temp);
        //System.out.println(JSON.toJSONString(jsonObject1,true));
        String jsonstr1= JSON.toJSONString(jsonObject1,true);
        String jsonstr2= JSON.toJSONString(jsonObject2,true);
        data.put("json1",jsonstr1);
        data.put("json2", jsonstr2);
        // 表格数据（第一个表格）
        data.put("list0", insertList);
        data.put("list1", insertList);
        data.put("list2", insertList);
        data.put("list3", insertList);//增删+批 共4个
        //一返回
        data.put("list4", fullList);
        data.put("list5", pageList);
        //一返回
        data.put("list6", fullList);
        data.put("list7", pageList);
        //一返回
        data.put("list8", fullList_ll);
    }

    public static void main(String[] args) {
        String  path = "D:\\word-template-engine\\src\\main\\resources\\";
        try {
            //            VelocityContext ctx = ;
            Map<String, Object> data = new LinkedHashMap<>();

            //setParam(data,new ReciveData());
           /* String[] urls=new String[]{"/c/v/1","/c/v/2","/c/v/3","/c/v/4","/c/v/5","/c/v/6","/c/v/7","/c/v/8"};

            List<Map<String, Object>> list = new ArrayList<>();

            for (int i = 0; i < 8; i++) {
                Map<String, Object> map = new LinkedHashMap<>();
                map.put("listparm1", i + 1);
                map.put("type1", "String");
                map.put("need1", "是");
                map.put("des1", "这是一个描述" + i);
                //map.put("img", path + i + ".jpg");
                list.add(map);
            }
            List<Map<String, Object>> list2 = new ArrayList<>();

            for (int i = 0; i < 4; i++) {
                Map<String, Object> map = new LinkedHashMap<>();
                map.put("listparm1", i + 1);
                map.put("type1", "String");
                map.put("need1", "是");
                map.put("des1", "这是一个描述" + i+System.currentTimeMillis());
                //map.put("img", path + i + ".jpg");
                list2.add(map);
            }

            List<Map<String, Object>> list3 = new ArrayList<>();

            for (int i = 0; i < 4; i++) {
                Map<String, Object> map = new LinkedHashMap<>();
                map.put("listparm1", i + 1);
                map.put("type1", "String");
                map.put("des1", "这是一个描述" + i+System.currentTimeMillis());
                //map.put("img", path + i + ".jpg");
                list3.add(map);
            }
            // 表格数据（第一个表格）
            data.put("list0", list);
            data.put("list1", list);
            data.put("list2", list);
            data.put("list3", list);//增删+批 共4个
            //一返回
            data.put("list4", list3);
            data.put("list5", list2);
            //一返回
            data.put("list6", list3);
            data.put("list7", list2);
            //一返回
            data.put("list8", list3);

            int n =0;
            for (String e:urls){
                data.put("url"+ (n+1),e);n++;
            }
            data.put("json1", "列表查询----------");
            data.put("json2", "分页返回描述----------");
            data.put("idsdes","主键描述");
            data.put("Title", "这是标题");
            data.put("Number", "0000001");
            data.put("Date", DateTime.now().toDateStr());*/

            System.out.println(JSONUtil.toJsonStr(data));
            MyWordTemplateEngineUtil.generator( "mydemo.docx", new VelocityContext(data));
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("出错了");
        }
    }
}
